﻿using System;
using System.Net;
using System.Web;
using System.Linq;
using System.Globalization;
using Stimulus360.Models.Cms;
using Stimulus360.Models.Data;
using Stimulus360.Repositories;
using System.Collections.Generic;
using Microsoft.ServiceModel.Web;
using System.ServiceModel.Activation;
using Stimulus360.Services.Interfaces;
using Stimulus360.Repositories.Interfaces;

namespace Stimulus360.Services
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class ProjectService : IProjectService
    {
        #region IProjectService Members

        /// <summary>
        ///     An instance of the IDataRepository to be used 
        /// </summary>
        private readonly IDataRepository _dataRepository;

        /// <summary>
        ///     An instance of the CMSService to be used for Project content
        /// </summary>
        private readonly ICmsService _cmsService;

        /// <summary>
        ///     Default constructor. Create the default DataRepository and CMS Service instances
        /// </summary>
        public ProjectService()
        {
            try
            {
                _dataRepository = new DataRepository();
                _cmsService = new CmsService();
            }
            catch (NullReferenceException exception)
            {
                // Exception conditions detected when invoking this service as a RESTFul service need to report an HTTP status code in the 
                //  400-500   range in addition to a message that details the exception
                throw new WebProtocolException(HttpStatusCode.BadGateway, "Could not connect to the database.Please check the connection and try again", exception);
            }
            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }

        /// <summary>
        ///     Dependency Injection enabled constructor. Sets the Data Repository and the CMS service to be used.
        /// </summary>
        /// <param name="repository">
        ///     The Data Repository instance to be used
        /// </param>
        /// <param name="service">
        ///     The CMS Service instance to be used
        /// </param>
        public ProjectService(IDataRepository repository, ICmsService service)
        {
            try
            {
                _dataRepository = repository ?? new DataRepository();
                _cmsService = service ?? new CmsService();

            }
            catch (NullReferenceException exception)
            {
                // Exception conditions detected when invoking this service as a RESTFul service need to report an HTTP status code in the 
                //  400-500   range in addition to a message that details the exception
                throw new WebProtocolException(HttpStatusCode.BadGateway, "Could not connect to the database.Please check the connection and try again", exception);
            }
            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }

        /// <summary>
        ///     Method to get all New Projects   
        /// </summary>
        /// <returns>
        ///     A List of all New Projects
        /// </returns>
        /// <remarks>
        ///     All parameters have been taken in string format to enable REST calls in the future
        /// </remarks>
        public PaginatedCollection<Project> GetNew(string pageNo, string pageSize)
        {
            try
            {
                pageNo = HttpUtility.HtmlEncode(pageNo);
                pageSize = HttpUtility.HtmlEncode(pageSize);

                var projList = _dataRepository.GetNewProjects();
                return new PaginatedCollection<Project>(projList, pageNo.ToInt(), pageSize.ToInt());
            }
            catch (ArgumentNullException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "One or more arguments provided are null", exception);
            }
            catch (FormatException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "One or more arguments provided are in invalid format",
                                               exception);
            }

            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "The Database context was null", exception);
            }
            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }

        /// <summary>
        ///     Method to get a list of projects in the given category
        /// </summary>
        /// <param name="category">
        ///     The category title for the given category
        /// </param>
        /// <param name="pageNo">
        ///     The Page number being displayed on the screen.
        /// </param>
        /// <param name="pageSize">
        ///     The number of projects being shown in the screen.
        /// </param>
        /// <returns>
        ///     A Paginated List of  Projects for the given category 
        ///     based on the page number and pagesize
        /// </returns>   
        /// <remarks>
        ///     All parameters have been taken in string format to enable REST calls in the future
        /// </remarks>
        public PaginatedCollection<Project> FindInCategory(string category, string pageNo, string pageSize)
        {
            try
            {
                category = HttpUtility.HtmlEncode(category);
                pageNo = HttpUtility.HtmlEncode(pageNo);
                pageSize = HttpUtility.HtmlEncode(pageSize);

                var projList = _dataRepository.FindProjectsInCategory(category);
                return new PaginatedCollection<Project>(projList, pageNo.ToInt(), pageSize.ToInt());
            }
            catch (ArgumentNullException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "One or more arguments provided are null", exception);
            }
            catch (FormatException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "One or more arguments provided are in invalid format",
                                               exception);
            }
            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "The Database context was null", exception);
            }

            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }

        /// <summary>
        ///     Method to find Projects based on the given search criteria.
        /// </summary>
        /// <param name="searchCriteria">
        ///     String representing the type of search criteria: ByStatus,ByDate,ByRanking
        /// </param>
        /// <param name="query">
        ///     Search string to be deciphered based on the search criteria.
        /// </param>
        /// <param name="pageNo">
        ///     The Page number being displayed on the screen.
        /// </param>
        /// <param name="pageSize">
        ///     The number of projects being shown in the screen.
        /// </param>
        /// <returns>
        ///     A Paginated List of  Projects for the givens earch criteria
        ///     based on the page number and pagesize
        /// </returns>   
        /// <remarks>
        ///     All parameters have been taken in string format to enable REST calls in the future
        /// </remarks>
        public PaginatedCollection<Project> Search(string searchCriteria, string query, string pageNo, string pageSize)
        {
            try
            {
                searchCriteria = HttpUtility.HtmlEncode(searchCriteria);
                query = HttpUtility.HtmlEncode(query);

                pageNo = HttpUtility.HtmlEncode(pageNo);
                pageSize = HttpUtility.HtmlEncode(pageSize);

                var criteria = (SearchCriteria)Enum.Parse(typeof(SearchCriteria), searchCriteria);
                IQueryable<Project> projList = null;
                switch (criteria)
                {

                    case SearchCriteria.Status:
                        var status = (ProjectStatus)Enum.Parse(typeof(ProjectStatus), query);
                        projList = _dataRepository.FindProjectsByStatus(status);
                        break;
                    case SearchCriteria.Top:
                        int ranking = int.Parse(query, CultureInfo.CurrentCulture);
                        projList = _dataRepository.GetTopNProjects(ranking);
                        break;
                    case SearchCriteria.Volunteers:
                        bool required = bool.Parse(query);
                        projList = _dataRepository.FindProjectsByVolunteerStatus(required);
                        break;
                    case SearchCriteria.SearchText:
                        projList = _dataRepository.FindProjectsBySearchString(query);
                        break;


                }

                return new PaginatedCollection<Project>(projList, pageNo.ToInt(), pageSize.ToInt());
            }
            catch (ArgumentException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "One or more arguments provided are invalid", exception);
            }
            catch (FormatException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "One or more arguments provided are in invalid format",
                                               exception);
            }
            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "The Database context was null", exception);
            }

            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }

        /// <summary>
        ///     Method to get Project details based on project Id
        /// </summary>
        /// <param name="projectId">
        ///     The project Id for which Project object is to be retrieved
        /// </param>
        /// <returns>
        ///     Project object for the given ProjectId
        /// </returns>
        /// <remarks>
        ///     All parameters have been taken in string format to enable REST calls in the future
        /// </remarks>
        public Project FindById(string projectId)
        {
            try
            {
                projectId = HttpUtility.HtmlEncode(projectId);

                Project project = _dataRepository.FindProjectById(projectId.ToInt());
                if (project != null)
                {
                    return project;
                }
                throw new WebProtocolException(HttpStatusCode.NotFound, "No project found for Project ID " + projectId, null);

            }
            catch (WebProtocolException)
            {
                throw;
            }
            catch (ArgumentNullException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "Project Id provided is null", exception);
            }
            catch (FormatException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "Project Id provided is in invalid format",
                                               exception);
            }

            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "The Database context was null", exception);
            }

            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }

        /// <summary>
        ///     Method to get a list of feedback for the given project.
        /// </summary>
        /// <param name="projectId">
        ///     ProjectID for the Project for which the feedback is to be retrieved
        /// </param>
        /// <param name="pageNo">
        ///     The Page number being displayed on the screen.
        /// </param>
        /// <param name="pageSize">
        ///     The number of feedbacks being shown in the screen.
        /// </param>
        /// <returns>
        ///     A Paginated List of feedback based on the page number and pagesize
        /// </returns>
        /// <remarks>
        ///     All parameters have been taken in string format to enable REST calls in the future
        /// </remarks>
        public PaginatedCollection<ProjectRating> GetFeedback(string projectId, string pageNo, string pageSize)
        {
            try
            {
                projectId = HttpUtility.HtmlEncode(projectId);
                pageNo = HttpUtility.HtmlEncode(pageNo);
                pageSize = HttpUtility.HtmlEncode(pageSize);

                var ratingList = _dataRepository.GetProjectFeedback(projectId.ToInt());
                return new PaginatedCollection<ProjectRating>(ratingList, pageNo.ToInt(), pageSize.ToInt());
            }
            catch (ArgumentNullException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "One or more arguments provided are null", exception);
            }
            catch (FormatException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "One or more arguments provided are in invalid format",
                                               exception);
            }


            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "The Database context was null", exception);
            }
            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }

        }

        /// <summary>
        ///     This method is used to get the User's feedback for a specific Project
        /// </summary>
        /// <param name="projectId">
        ///     ProjectID for which feedback is to be retrieved.
        /// </param>
        /// <param name="userName">
        ///     User whose feedback is to be retrieved
        /// </param>
        /// <returns>
        ///     User Feedback for the given project.
        /// </returns>
        /// <remarks>
        ///     All parameters have been taken in string format to enable REST calls in the future
        /// </remarks>
        public ProjectRating GetFeedback(string userName, string projectId)
        {
            try
            {
                userName = HttpUtility.HtmlEncode(userName);
                projectId = HttpUtility.HtmlEncode(projectId);
                return _dataRepository.GetProjectFeedback(projectId.ToInt(), userName);
            }
            catch (ArgumentNullException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "Project Id provided is null", exception);
            }
            catch (FormatException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "Project Id provided is in invalid format",
                                               exception);
            }



            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "The Database context was null", exception);
            }
            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }

        /// <summary>
        ///     Method to add feedback for a given Project
        /// </summary>
        /// <param name="feedback">
        ///     The feedback to be added
        /// </param>
        /// <remarks>
        ///     Input parameter type will need to change if method is exposed as REST.
        ///     also User Authentication will need to be implemented
        /// </remarks>
        public void AddFeedback(ProjectRating feedback)
        {
            try
            {
                if (feedback != null && feedback.IsValid)
                {
                    Project projRated = _dataRepository.FindProjectById(feedback.ProjectId);
                    if (projRated != null)
                    {
                        projRated.ProjectRatings.Add(feedback);
                        if (feedback.Favorite == true)
                        {
                            projRated.FavoritesCount = projRated.FavoritesCount.GetValueOrDefault(0) + 1;

                        }
                        double rating = projRated.AverageRating.GetValueOrDefault(0) *
                                        projRated.UserRatingsCount.GetValueOrDefault(0);

                        projRated.UserRatingsCount = projRated.UserRatingsCount.GetValueOrDefault(0) + 1;
                        projRated.AverageRating = (rating + feedback.Rating) / projRated.UserRatingsCount;
                        _dataRepository.UpdateProject();
                    }
                    else
                    {
                        throw new WebProtocolException(HttpStatusCode.NotFound,
                                                       "No project found for Project ID " + feedback.ProjectId, null);

                    }
                }
                else
                {
                    throw new WebProtocolException(HttpStatusCode.BadRequest, "Feedback Provided was null/invalid", null);

                }
            }

            catch (WebProtocolException)
            {
                throw;
            }
            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "One or more objects was null", exception);
            }

            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }

        /// <summary>
        ///     Method to retrieve documents for a given project
        /// </summary>
        /// <param name="projectId">
        ///     Project for which documents are to be retrieved
        /// </param>
        /// <param name="pageNo">
        ///     Page number to be displayed
        /// </param>
        /// <param name="pageSize">
        ///     The number of documents to be displayed
        /// </param>
        /// <returns>
        ///     Documents for the given project
        /// </returns>
        /// <remarks>
        ///     All parameters have been taken in string format to enable REST calls in the future
        /// </remarks>
        public PaginatedCollection<ProjectDocument> GetDocuments(string projectId, string pageNo, string pageSize)
        {
            try
            {
                projectId = HttpUtility.HtmlEncode(projectId);
                pageNo = HttpUtility.HtmlEncode(pageNo);
                pageSize = HttpUtility.HtmlEncode(pageSize);

                return _cmsService.GetDocuments(projectId.ToInt(), pageNo.ToInt(), pageSize.ToInt());
            }
            catch (ArgumentNullException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "One or more arguments provided are null", exception);
            }
            catch (FormatException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "One or more arguments provided are in invalid format",
                                               exception);
            }

            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "The Database Context was null", exception);
            }
            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }

        /// <summary>
        ///     Method to add a document to the given project
        /// </summary>
        /// <param name="document">
        ///     The document to be added
        /// </param>
        /// <remarks>
        ///     Input parameter type will need to change if method is exposed as REST.
        ///     also User Authentication will need to be implemented
        /// </remarks>
        public void AddDocument(ProjectDocument document)
        {
            try
            {
                if (document != null && document.IsValid)
                {
                    _cmsService.AddDocument(document);
                }
                else
                {
                    throw new WebProtocolException(HttpStatusCode.BadRequest, "Document Provided was null/invalid", null);
                }
            }
            catch (WebProtocolException)
            {
                throw;
            }
            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "The Database Context was null", exception);
            }

            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }

        /// <summary>
        ///     Method to retrieve photos for a given project
        /// </summary>
        /// <param name="projectId">
        ///     Project for which photos are to be retrieved
        /// </param>
        /// <param name="pageNo">
        ///     Page number to be displayed
        /// </param>
        /// <param name="pageSize">
        ///     The number of photos to be displayed
        /// </param>
        /// <returns>
        ///     Photos for the given project
        /// </returns>
        /// <remarks>
        ///     All parameters have been taken in string format to enable REST calls in the future
        /// </remarks>
        public PaginatedCollection<ProjectPhoto> GetPhotos(string projectId, string pageNo, string pageSize)
        {
            try
            {
                projectId = HttpUtility.HtmlEncode(projectId);
                pageNo = HttpUtility.HtmlEncode(pageNo);
                pageSize = HttpUtility.HtmlEncode(pageSize);

                return _cmsService.GetPhotos(projectId.ToInt(), pageNo.ToInt(), pageSize.ToInt());
            }
            catch (ArgumentNullException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "One or more arguments provided are null", exception);
            }
            catch (FormatException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "One or more arguments provided are in invalid format",
                                               exception);
            }
            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "The Database Context was null", exception);
            }
            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }

        }

        /// <summary>
        ///     Method to add a photo to the project details
        /// </summary>
        /// <param name="photo">
        ///     The photo to be added
        /// </param>
        /// <remarks>
        ///     Input parameter type will need to change if method is exposed as REST.
        ///     also User Authentication will need to be implemented
        /// </remarks>
        public void AddPhoto(ProjectPhoto photo)
        {
            try
            {
                if (photo != null && photo.IsValid)
                {
                    _cmsService.AddPhoto(photo);
                }
                else
                {
                    throw new WebProtocolException(HttpStatusCode.BadRequest, "Photo Provided was null/invalid", null);
                }
            }
            catch (WebProtocolException)
            {
                throw;
            }
            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "The Database Context was null",
                                               exception);
            }

            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }

        /// <summary>
        ///     Method to retrieve a paginated list of volunteers for the given project
        /// </summary>
        /// <param name="projectId">
        ///     Project ID for which list of volunteers is to be retrieved
        /// </param>
        /// <param name="pageNo">
        ///     The page number being viewed
        /// </param>
        /// <param name="pageSize">
        ///     The number of volunteers displayed per page.
        /// </param>
        /// <returns>
        ///     List of volunteers for the given project
        /// </returns>
        /// <remarks>
        ///     All parameters have been taken in string format to enable REST calls in the future
        /// </remarks>
        public PaginatedCollection<Volunteer> GetVolunteers(string projectId, string pageNo, string pageSize)
        {
            try
            {
                projectId = HttpUtility.HtmlEncode(projectId);
                pageNo = HttpUtility.HtmlEncode(pageNo);
                pageSize = HttpUtility.HtmlEncode(pageSize);

                var volList = _dataRepository.GetProjectVolunteers(projectId.ToInt());
                return new PaginatedCollection<Volunteer>(volList, pageNo.ToInt(), pageSize.ToInt());
            }
            catch (ArgumentNullException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "One or more arguments provided are null", exception);
            }
            catch (FormatException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "One or more arguments provided are in invalid format",
                                               exception);
            }
            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "The Database Context was null", exception);
            }
            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }

        /// <summary>
        ///     Method to add a volunteer to a project
        /// </summary>
        /// <param name="volunteer">
        ///     Volunteer to be added
        /// </param>
        /// <param name="projectId">
        ///     Project in which the volunteer is interested.
        /// </param>
        /// <remarks>
        ///     Input parameter type will need to change if method is exposed as REST.
        ///     also User Authentication will need to be implemented
        /// </remarks>
        public void AddVolunteer(Volunteer volunteer, int projectId)
        {
            try
            {
                if (volunteer != null)
                {
                    Project project = _dataRepository.FindProjectById(projectId);
                    if (project != null)
                    {
                        project.Volunteers.Add(volunteer);
                        _dataRepository.UpdateProject();
                    }
                    else
                    {
                        throw new WebProtocolException(HttpStatusCode.NotFound,
                                                       "No Project found for project Id: " + projectId, null);
                    }
                }
                else
                {
                    throw new WebProtocolException(HttpStatusCode.BadRequest, "Volunteer was null", null);
                }
            }
            catch (WebProtocolException)
            {
                throw;
            }
            catch (ArgumentException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "One or more arguments provided are invalid", exception);
            }
            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "The Database Context was null", exception);
            }
            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }

        /// <summary>
        ///     Method to get list of projects related to the given project
        /// </summary>
        /// <param name="projectId">
        ///     ProjectID for which related list is to be retrieved
        /// </param>
        /// <returns>
        ///     List of related projects.
        /// </returns>
        /// <remarks>
        ///     All parameters have been taken in string format to enable REST calls in the future
        /// </remarks>
        public ICollection<Project> GetRelated(string projectId)
        {
            try
            {
                projectId = HttpUtility.HtmlEncode(projectId);

                Project project = _dataRepository.FindProjectById(projectId.ToInt());
                if (project != null)
                {
                    return (from relatedProject in _dataRepository.FindProjectsInCategory(project.InvestmentCategory.Category)
                            where relatedProject.Status != (byte)ProjectStatus.Cancelled && relatedProject.ProjectId != projectId.ToInt()
                            orderby relatedProject.DateCreated descending
                            select relatedProject).Take(10).ToList();

                }
                throw new WebProtocolException(HttpStatusCode.NotFound, "No project found for Project Id: " + projectId,
                                               null);
            }
            catch (WebProtocolException)
            {
                throw;
            }
            catch (ArgumentNullException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "Project Id provided is null", exception);
            }
            catch (FormatException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "Project Id provided is in invalid format",
                                               exception);
            }


            catch (NullReferenceException exception)
            {

                throw new WebProtocolException(HttpStatusCode.InternalServerError, "The Database context was null", exception);
            }
            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }

        }

        /// <summary>
        ///     Method to get all New Projects 
        /// </summary>
        /// <returns>
        ///     A List of all New Projects
        /// </returns>
        public IEnumerable<Project> GetNew()
        {
            try
            {
                return _dataRepository.GetNewProjects().ToList();
            }
            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "The Database Context was null", exception);
            }
            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }

        /// <summary>
        ///    Method used for RSS Feeds to get list of most popular projects.
        /// </summary>
        /// <returns>
        ///     List of Most popular Projects.
        /// </returns>
        /// <remarks>
        ///     All parameters have been taken in string format to enable REST calls in the future
        /// </remarks>
        public IEnumerable<Project> GetTopN(string topN)
        {
            try
            {
                topN = HttpUtility.HtmlEncode(topN);

                return _dataRepository.GetTopNProjects(topN.ToInt()).ToList();
            }
            catch (ArgumentNullException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "Ranking provided is null", exception);
            }
            catch (FormatException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "Ranking provided is in invalid format",
                                               exception);
            }


            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "The Database context was null", exception);
            }
            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }

        /// <summary>
        ///     Method to retrieve a photo by its ID
        /// </summary>
        /// <param name="photoId">
        ///     The Photo ID to be retrieved
        /// </param>
        /// <returns>
        ///     The Photo for the given ID
        /// </returns>
        /// <remarks>
        ///     All parameters have been taken in string format to enable REST calls in the future
        /// </remarks>
        public ProjectPhoto FindPhotoById(string photoId)
        {
            try
            {
                photoId = HttpUtility.HtmlEncode(photoId);
                ProjectPhoto photo = _cmsService.FindPhotoById(photoId.ToInt());
                if (photo != null)
                {
                    return photo;
                }
                throw new WebProtocolException(HttpStatusCode.NotFound, "No Photo found for Photo Id: " + photoId,
                                               null);
            }
            catch (WebProtocolException)
            {
                throw;
            }
            catch (ArgumentNullException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "Photo Id provided is null", exception);
            }
            catch (FormatException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "Photo Id provided is in invalid format",
                                               exception);
            }


            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "The Database context was null", exception);
            }
            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }

        /// <summary>
        ///     Method to retrieve a document based on its ID
        /// </summary>
        /// <param name="documentId">
        ///     ID for which document is to be retrieved
        /// </param>
        /// <returns>
        ///     Document  based on the given ID.
        /// </returns>
        /// <remarks>
        ///     All parameters have been taken in string format to enable REST calls in the future
        /// </remarks>
        public ProjectDocument FindDocumentById(string documentId)
        {
            try
            {
                documentId = HttpUtility.HtmlEncode(documentId);
                ProjectDocument document = _cmsService.FindDocumentById(documentId.ToInt());
                if (document != null)
                {
                    return document;
                }
                throw new WebProtocolException(HttpStatusCode.NotFound, "No Document found for Document Id: " + documentId,
                                     null);
            }
            catch (WebProtocolException)
            {
                throw;
            }
            catch (ArgumentNullException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "Document Id provided is null", exception);
            }
            catch (FormatException exception)
            {
                throw new WebProtocolException(HttpStatusCode.BadRequest, "Document Id provided is in invalid format",
                                               exception);
            }


            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "The Database context was null", exception);
            }
            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }

        /// <summary>
        ///     This method is used to create a new project in the DB
        /// </summary>
        /// <param name="project">
        ///     The project to be created
        /// </param>
        /// <remarks>
        ///     Input parameter type will need to change if method is exposed as REST.
        ///     also User Authentication will need to be implemented
        /// </remarks>
        public int Add(Project project)
        {
            try
            {
                if (project != null)
                {
                    _dataRepository.CreateProject(project);
                    int completedProjCount = project.InvestmentCategory.CompletedProjectCount.GetValueOrDefault(0);
                    double score = project.InvestmentCategory.Score.GetValueOrDefault(0);
                    project.InvestmentCategory.CompletedProjectCount = completedProjCount + 1;
                    project.InvestmentCategory.Score = score + 1;
                    _dataRepository.UpdateProject();
                    return project.ProjectId;
                }
                throw new WebProtocolException(HttpStatusCode.BadRequest, "Project was null", null);
            }
            catch (WebProtocolException)
            {
                throw;
            }
            catch (NullReferenceException exception)
            {
                throw new WebProtocolException(HttpStatusCode.InternalServerError, "One or more objects was null", exception);
            }
            catch (Exception exception)
            {
                throw new WebProtocolException(ExceptionHelper.GetStatusCode(exception), exception.Message, exception);
            }
        }
        #endregion

    }
}
